#include "Disk.h"
#include "Position.h"
#include <iostream>
#include <math.h>

using namespace std;

Disk::Disk()
{
	minseek=0.6; // TODO: Change this value!
	maxseek=17; // TODO: Change this value!
	avgseek=8;
	contOverhead =2;
	RPM = 0.12; // 7200 / (60s/min) / (1000ms/s)
	preciseSeek = true;
	transferSize = 8*1024;
	transferRate = 4*1024*1024/1000;
	curTrack =0;
	curSector =0;
	changed = false;
}

Disk::Disk(int t, int s, int b) : tracks(t), sectorsPerTrack(s), bytesPerSector(b)
{
	curTrack =0;
	curSector =0;
	minseek=0.6; // TODO: Change this value!
	maxseek=17; // TODO: Change this value!
	avgseek=8;
	contOverhead =2;
	RPM = 0.12; // 7200 / (60s/min) / (1000ms/s)
	preciseSeek = true;
	transferSize = 8*1024;
	transferRate = 4*1024*1024/1000;
	changed = false;
}

Disk::~Disk()
{
}

double Disk::seekTime(Position at, Position to)
{
	int Tat = at.track;
	int Tto = to.track;
//	cout << "Tat: " << at.track << endl;
//	cout << "Tto: " << to.track << endl;
	int dif = Tto-Tat;
	if(dif <0)
		dif = (-1)*dif;
	if(Tat==Tto)
		return 0;	
	if(preciseSeek)
	{
		double a = (-10*minseek + 15*avgseek - 5*maxseek)/(3*sqrt(tracks));
		double b = (7*minseek - 15*avgseek + 8*maxseek)/(3*tracks);
		return (a*sqrt(dif-1) + b*(dif-1) + minseek);
	
	}
	return (minseek +  (dif*3/tracks)*(avgseek - minseek));

}

double Disk::rotDelay()
{
	return 0.5/RPM;
}

double Disk::treatReq(Requisition req)
{
	int totalSize = req.size;
	if ((req.size%transferSize) != 0)
		totalSize += (8*1024 - (req.size%transferSize));
//	cout << "TotalSize: " << totalSize << endl;
	int trackChanges = totalSize/(sectorsPerTrack*bytesPerSector);
	if(totalSize%(sectorsPerTrack*bytesPerSector)==0)
		trackChanges--;
	Position cur;
	cur.track = curTrack;
	cur.sector = curSector;
	Position to;
	to.track = req.track;
	to.sector = req.sector;
	
	int numBlocks;
	numBlocks = req.size/transferSize;
	if(req.size%transferSize !=0)
		numBlocks++;
	
//	cout << " From: " << cur.track << ", " << cur.sector << " to " << to.track << ", " << to.sector<< endl;
	double totalTime = 0;
	if (!changed) {
		totalTime += seekTime(cur, to) + trackChanges*minseek;
	}
//	cout << "trackChanges: " << trackChanges << endl;
//	cout << "Total seek time: " << totalTime << endl;
	totalTime +=  contOverhead;
	totalTime += (trackChanges+1)*rotDelay();
	totalTime +=  transferSize*numBlocks/transferRate;
//	cout << "Total Rot. Delay: " << (trackChanges+1)*rotDelay() << endl;
//	cout << "Total Trans. Time: " << transferSize*numBlocks/transferRate << endl;

	if (changed) {
//		cout << "Baggio se passou" << endl;
		changed = false;
		if (to.track > cur.track) {
			totalTime += seekTime(cur, Position(0, 0) ) + seekTime (Position(0, 0), to);
			cout << "Total extra seek time: " << seekTime(cur, Position(0, 0) ) + seekTime (Position(0, 0), to) << endl;
		}
		else {
			totalTime += seekTime(cur, Position(tracks-1, 0) ) + seekTime(Position(tracks-1, 0), to );
			cout << "Total extra seek time: " << seekTime(cur, Position(tracks-1, 0) ) + seekTime(Position(tracks-1, 0), to ) << endl;
		}
	}
	curTrack = (to.track + trackChanges)%tracks;
//	if (curTrack >= tracks)
//		curTrack = tracks-1;
	curSector = to.sector;
//	cout << "tt: " << totalTime << endl;
	return totalTime;
}

Position Disk::getPos()
{
	Position p;
	p.track = curTrack;
	p.sector = curSector;
	return p;
}